#include "STM_ST7789.h"
#define TFT_HARD_SPI 0 ///< 硬件SPI
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif
#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
#else
#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
#endif

inline GFXglyph* pgm_read_glyph_ptr(const GFXfont* gfxFont, uint8_t c) {
  return gfxFont->glyph + c;
}

inline uint8_t* pgm_read_bitmap_ptr(const GFXfont* gfxFont) {
  return gfxFont->bitmap;
}

#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif

#ifndef _swap_int16_t
#define _swap_int16_t(a, b)                                                    \
  {                                                                            \
    int16_t t = a;                                                             \
    a = b;                                                                     \
    b = t;                                                                     \
  }
#endif

STM_ST7789::STM_ST7789(SPIDMAClass* spiClass, int8_t cs, int8_t dc, int8_t rst) {
  _spi = spiClass;
  connection = TFT_HARD_SPI;
  _rst = rst;
  _cs = cs;
  _dc = dc;
  _width = 240;
  _height = 320;
  rotation = 0;
  cursor_y = cursor_x = 0;
  textcolor = textbgcolor = 0xFFFF;
  wrap = true;
  _cp437 = false;
  gfxFont = NULL;
}

void STM_ST7789::begin(uint16_t width, uint16_t height) {
  invertOnCommand = ST77XX_INVON;
  invertOffCommand = ST77XX_INVOFF;
  pinMode(_cs, OUTPUT);
  digitalWrite(_cs, HIGH); // Deselect
  pinMode(_dc, OUTPUT);
  digitalWrite(_dc, HIGH); // Data mode
  if (width == 240 && height == 240) {
    // 1.3", 1.54" displays (right justified)
    _rowstart = (320 - height);
    _rowstart2 = 0;
    _colstart = _colstart2 = (240 - width);
  }
  else if (width == 135 && height == 240) {
    // 1.14" display (centered, with odd size)
    _rowstart = _rowstart2 = (int)((320 - height) / 2);
    _colstart = (int)((240 - width + 1) / 2);
    _colstart2 = (int)((240 - width) / 2);
  }
  else {
    // 1.47", 1.69, 1.9", 2.0" displays (centered)
    _rowstart = _rowstart2 = (int)((320 - height) / 2);
    _colstart = _colstart2 = (int)((240 - width) / 2);
  }

  windowWidth = width;
  windowHeight = height;

  displayInit(generic_st7789);
  setRotation(0);
}

void STM_ST7789::setRotation(uint8_t m) {
  uint8_t madctl = 0;

  rotation = m & 3; // can't be higher than 3

  switch (rotation) {
  case 0:
    madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB;
    _xstart = _colstart;
    _ystart = _rowstart;
    _width = windowWidth;
    _height = windowHeight;
    break;
  case 1:
    madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB;
    _xstart = _rowstart;
    _ystart = _colstart2;
    _height = windowWidth;
    _width = windowHeight;
    break;
  case 2:
    madctl = ST77XX_MADCTL_RGB;
    _xstart = _colstart2;
    _ystart = _rowstart2;
    _width = windowWidth;
    _height = windowHeight;
    break;
  case 3:
    madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB;
    _xstart = _rowstart2;
    _ystart = _colstart;
    _height = windowWidth;
    _width = windowHeight;
    break;
  }
  sendCommand(ST77XX_MADCTL, &madctl, 1);
}

void STM_ST7789::displayInit(const uint8_t* addr) {
  uint8_t numCommands, cmd, numArgs;
  uint16_t ms;
  numCommands = pgm_read_byte(addr++); // 要遵循的命令数
  while (numCommands--) {              // 对于每个命令。。。
    cmd = pgm_read_byte(addr++);       // 读取命令
    numArgs = pgm_read_byte(addr++);   // 要跟随的参数数
    ms = numArgs & ST_CMD_DELAY;       // 如果设置了hibit，则延迟跟随参数
    numArgs &= ~ST_CMD_DELAY;          // 屏蔽延迟位
    sendCommand(cmd, addr, numArgs);
    addr += numArgs;

    if (ms) {
      ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
      if (ms == 255)
        ms = 500; // If 255, delay for 500 ms
      delay(ms);
    }
  }
}

void STM_ST7789::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
  x += _xstart;
  y += _ystart;
  uint32_t xa = ((uint32_t)x << 16) | (x + w - 1);
  uint32_t ya = ((uint32_t)y << 16) | (y + h - 1);

  writeCommand(ST77XX_CASET); // Column addr set
  SPI_WRITE32(xa);

  writeCommand(ST77XX_RASET); // Row addr set
  SPI_WRITE32(ya);

  writeCommand(ST77XX_RAMWR); // write to RAM
}

void STM_ST7789::setColRowStart(int8_t col, int8_t row) {
  _colstart = col;
  _rowstart = row;
}

void STM_ST7789::enableDisplay(boolean enable) {
  sendCommand(enable ? ST77XX_DISPON : ST77XX_DISPOFF);
}

void STM_ST7789::enableTearing(boolean enable) {
  sendCommand(enable ? ST77XX_TEON : ST77XX_TEOFF);
}

void STM_ST7789::enableSleep(boolean enable) {
  sendCommand(enable ? ST77XX_SLPIN : ST77XX_SLPOUT);
}
//  在所需坐标处为显示器绘制一个像素
void STM_ST7789::writePixel(int16_t x, int16_t y, uint16_t color) {
  if ((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
    setAddrWindow(x, y, 1, 1);
    SPI_WRITE16(color);
  }
}
//从内存向显示器发出一系列像素。不是自我包含；应该跟随startWrite（）和setAddrWindow（）调用。
//colors     指向'565'RGB格式的16位像素值数组的指针.
//len        “colors”数组中的元素数。
//block      如果为true（如果未指定，则为默认情况），则功能将停止，直到DMA传输完成。
//如果没有启用DMA，这只是忽略。如果为false，该函数将在最后一次DMA传输开始后立即返回，
//并且在执行任何其他与显示相关的活动（或者甚至任何与SPI相关的活动，
//如果使用与其他设备共享总线的SPI显示器）之前，应使用dmaWait（）函数。
//bigEndian  如果为true，则内存中的位图按大端序排列（最高有效字节优先）。
//默认情况下，这是错误的，因为大多数微控制器似乎都是小端序，
//并且在发布到显示器之前必须对16位像素值进行字节交换（当使用SPI或8位并行时，
//这倾向于大端序）。如果应用程序可以围绕这一点进行优化——例如，
//uint16_t数组中字节值已排序为big-endian的位图，这可以在这里节省时间，
//特别是如果使用此函数的非阻塞DMA模式。
void STM_ST7789::writePixels(uint16_t* colors, uint32_t len) {
  uint8_t code [4096];
  uint32_t i = 0;
  if (!len)
    return;
  if (len < 2049) {
    while (len--) {
      code [i] = (*colors++) >> 8;
      code [i++] = (*colors++) & 0xFF;
      i += 2;
    }
    SPI_DMAARRAY(code, len * 2);
  }
  else {
    while (len--) {
      code [i] = (*colors++) >> 8;
      code [i++] = (*colors++) & 0xFF;
      i += 2;
      if (i == 4096) {
        SPI_DMAARRAY(code, len * 2);
        i = 0;
      }
    }
    if (len % 2048) {
      SPI_DMAARRAY(code, (len % 2048) * 2);
    }
  }
}

void STM_ST7789::writeColor(uint16_t color, uint32_t len) {
  uint8_t hi = color >> 8, lo = color & 0xFF;
  uint16_t ii = 0;
  uint32_t i;
  uint8_t code [4096], len_mx;
  if (len < 2049) {
    for (i = 0;i < len;i++) {
      code [ii] = hi;
      code [ii + 1] = lo;
      ii += 2;
    }
    SPI_DMAARRAY(code, len * 2);
  }
  else {
    for (i = 0;i < (len * 2);i++) {
      code [ii] = hi;
      code [ii + 1] = lo;
      ii += 2;
      if (ii == 4096) {
        SPI_DMAARRAY(code, 4096);
        ii = 0;
      }
    }
    if (len % 2048) {
      SPI_DMAARRAY(code, (len % 2048) * 2);
    }
  }

}
//在显示器上绘制一个填充矩形
void STM_ST7789::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
  if (w && h) {   // Nonzero width and height?
    if (w < 0) {  // If negative width...
      x += w + 1; //   Move X to left edge
      w = -w;     //   Use positive width
    }
    if (x < _width) { // Not off right
      if (h < 0) {    // If negative height...
        y += h + 1;   //   Move Y to top edge
        h = -h;       //   Use positive height
      }
      if (y < _height) { // Not off bottom
        int16_t x2 = x + w - 1;
        if (x2 >= 0) { // Not off left
          int16_t y2 = y + h - 1;
          if (y2 >= 0) { // Not off top
            // Rectangle partly or fully overlaps screen
            if (x < 0) {
              x = 0;
              w = x2 + 1;
            } // Clip left
            if (y < 0) {
              y = 0;
              h = y2 + 1;
            } // Clip top
            if (x2 >= _width) {
              w = _width - x;
            } // Clip right
            if (y2 >= _height) {
              h = _height - y;
            } // Clip bottom
            writeFillRectPreclipped(x, y, w, h, color);
          }
        }
      }
    }
  }
}
//在显示器上画一条水平线。
void inline STM_ST7789::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
  if ((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width
    if (w < 0) {                        // If negative width...
      x += w + 1;                       //   Move X to left edge
      w = -w;                           //   Use positive width
    }
    if (x < _width) { // Not off right
      int16_t x2 = x + w - 1;
      if (x2 >= 0) { // Not off left
        // Line partly or fully overlaps screen
        if (x < 0) {
          x = 0;
          w = x2 + 1;
        } // Clip left
        if (x2 >= _width) {
          w = _width - x;
        } // Clip right
        writeFillRectPreclipped(x, y, w, 1, color);
      }
    }
  }
}
//在显示器上画一条垂直线。
void inline STM_ST7789::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
  if ((x >= 0) && (x < _width) && h) { // X on screen, nonzero height
    if (h < 0) {                       // If negative height...
      y += h + 1;                      //   Move Y to top edge
      h = -h;                          //   Use positive height
    }
    if (y < _height) { // Not off bottom
      int16_t y2 = y + h - 1;
      if (y2 >= 0) { // Not off top
        // Line partly or fully overlaps screen
        if (y < 0) {
          y = 0;
          h = y2 + 1;
        } // Clip top
        if (y2 >= _height) {
          h = _height - y;
        } // Clip bottom
        writeFillRectPreclipped(x, y, 1, h, color);
      }
    }
  }
}

inline void STM_ST7789::writeFillRectPreclipped(int16_t x, int16_t y,
  int16_t w, int16_t h, uint16_t color) {
  setAddrWindow(x, y, w, h);
  writeColor(color, w * h);
}
//在所需坐标处为显示器绘制一个像素
void STM_ST7789::drawPixel(int16_t x, int16_t y, uint16_t color) {
  // Clip first...
  if ((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
    // THEN set up transaction (if needed) and draw...
    SPI_BEGIN_TRANSACTION();
    setAddrWindow(x, y, 1, 1);
    SPI_WRITE16(color);
    SPI_END_TRANSACTION();
  }
}
void STM_ST7789::drawarray(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* array) {
  SPI_BEGIN_TRANSACTION();
  setAddrWindow(x, y, w, h);
  SPI_DMAARRAY(array, w * h * 2);
  SPI_END_TRANSACTION();
}
//在显示器上绘制一个填充矩形
void STM_ST7789::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
  SPI_BEGIN_TRANSACTION();
  writeFillRectPreclipped(x, y, w, h, color);
  SPI_END_TRANSACTION();
}
//在显示器上画一条水平线
void STM_ST7789::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
  if ((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width
    if (w < 0) {                        // If negative width...
      x += w + 1;                       //   Move X to left edge
      w = -w;                           //   Use positive width
    }
    if (x < _width) { // Not off right
      int16_t x2 = x + w - 1;
      if (x2 >= 0) { // Not off left
        // Line partly or fully overlaps screen
        if (x < 0) {
          x = 0;
          w = x2 + 1;
        } // Clip left
        if (x2 >= _width) {
          w = _width - x;
        } // Clip right
        SPI_BEGIN_TRANSACTION();
        writeFillRectPreclipped(x, y, w, 1, color);
        SPI_END_TRANSACTION();
      }
    }
  }
}
//在显示器上画一条垂直线。
void STM_ST7789::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
  if ((x >= 0) && (x < _width) && h) { // X on screen, nonzero height
    if (h < 0) {                       // If negative height...
      y += h + 1;                      //   Move Y to top edge
      h = -h;                          //   Use positive height
    }
    if (y < _height) { // Not off bottom
      int16_t y2 = y + h - 1;
      if (y2 >= 0) { // Not off top
        // Line partly or fully overlaps screen
        if (y < 0) {
          y = 0;
          h = y2 + 1;
        } // Clip top
        if (y2 >= _height) {
          h = _height - y;
        } // Clip bottom
        SPI_BEGIN_TRANSACTION();
        writeFillRectPreclipped(x, y, 1, h, color);
        SPI_END_TRANSACTION();
      }
    }
  }
}
//画线
void STM_ST7789::drawRGBBitmap(int16_t x, int16_t y, uint16_t* pcolors, int16_t w, int16_t h) {

  int16_t x2, y2;                 // 右下坐标
  if ((x >= _width) ||            // Off-edge right
    (y >= _height) ||           // " top
    ((x2 = (x + w - 1)) < 0) || // " left
    ((y2 = (y + h - 1)) < 0))
    return; // " bottom

  int16_t bx1 = 0, by1 = 0, // Clipped top-left within bitmap
    saveW = w;            // Save original bitmap width value
  if (x < 0) {              // Clip left
    w += x;
    bx1 = -x;
    x = 0;
  }
  if (y < 0) { // Clip top
    h += y;
    by1 = -y;
    y = 0;
  }
  if (x2 >= _width)
    w = _width - x; // Clip right
  if (y2 >= _height)
    h = _height - y; // Clip bottom

  pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
  SPI_BEGIN_TRANSACTION();
  setAddrWindow(x, y, w, h); // Clipped area
  while (h--) {              // For each (clipped) scanline...
    writePixels(pcolors, w); // Push one (clipped) row
    pcolors += saveW;        // Advance pointer by one full (unclipped) line
  }
  SPI_END_TRANSACTION();
}
//反转显示器的颜色（如果硬件支持）。
void STM_ST7789::invertDisplay(bool i) {
  SPI_BEGIN_TRANSACTION();
  writeCommand(i ? invertOnCommand : invertOffCommand);
  SPI_END_TRANSACTION();
}
// 给定8位红色、绿色和蓝色值，返回“565”RGB格式的“压缩”16位颜色值（5位红色、6位绿色、5位蓝色）。这只是一个数学运算，没有涉及任何硬件。

uint16_t STM_ST7789::color565(uint8_t red, uint8_t green, uint8_t blue) {
  return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}

void STM_ST7789::sendCommand(uint8_t commandByte, uint8_t* dataBytes, uint8_t numDataBytes) {
  SPI_BEGIN_TRANSACTION();
  writeCommand(commandByte); // 发送命令字节
  for (int i = 0; i < numDataBytes; i++) {
    spiWrite(*dataBytes); // 发送数据字节
    dataBytes++;
  }
  SPI_END_TRANSACTION();
}

void STM_ST7789::sendCommand(uint8_t commandByte, const uint8_t* dataBytes, uint8_t numDataBytes) {
  SPI_BEGIN_TRANSACTION();
  writeCommand(commandByte);
  for (int i = 0; i < numDataBytes; i++) {
    spiWrite(pgm_read_byte(dataBytes++));
  }
  SPI_END_TRANSACTION();
}

void STM_ST7789::sendCommand16(uint16_t commandWord, const uint8_t* dataBytes, uint8_t numDataBytes) {
  SPI_BEGIN_TRANSACTION();
  if (numDataBytes == 0) {
    SPI_DC_LOW();             // Command mode
    SPI_WRITE16(commandWord); // Send the command word
    SPI_DC_HIGH();            // Data mode
  }
  for (int i = 0; i < numDataBytes; i++) {
    SPI_DC_LOW();             // Command mode
    SPI_WRITE16(commandWord); // Send the command word
    SPI_DC_HIGH();            // Data mode
    commandWord++;
    SPI_WRITE16((uint16_t)pgm_read_byte(dataBytes++));
  }
  SPI_END_TRANSACTION();
}
/*开启spi总线
*/
inline void STM_ST7789::SPI_BEGIN_TRANSACTION(void) {
  //SPI_SPEED_CLOCK_DEFAULT, MSBFIRST, SPI_MODE0, SPI_TRANSMITRECEIVE
  _spi->begin();//beginTransaction(SPISettings(36*1000*1000, MSBFIRST, SPI_MODE0));
  digitalWrite(_cs, LOW);
}

/*结束spi总线
*/
inline void STM_ST7789::SPI_END_TRANSACTION(void) {
  digitalWrite(_cs, HIGH);
  _spi->end();
}

/*写8位数据
*/
void STM_ST7789::spiWrite(uint8_t b) {
  _spi->transfer(b);
}

/*写8位命令数据
*/
void STM_ST7789::writeCommand(uint8_t cmd) {
  SPI_DC_LOW();
  spiWrite(cmd);
  SPI_DC_HIGH();
}

/*传输16位数据
*/
void STM_ST7789::write16(uint16_t w) {
  _spi->transfer16(w);
}

/*传输16位命令数据
*/
void STM_ST7789::writeCommand16(uint16_t cmd) {
  SPI_DC_LOW();
  write16(cmd);
  SPI_DC_HIGH();
}
//写入16位数据
void STM_ST7789::SPI_WRITE16(uint16_t w) {
  _spi->transfer16(w);
}

/* 传输32位数据
*/
void STM_ST7789::SPI_WRITE32(uint32_t l) {
  uint8_t code [4];
  code [0] = l >> 24;
  code [1] = l >> 16;
  code [2] = l >> 8;
  code [3] = l & 0xFF;
  _spi->transfer(code, 4);
}

void STM_ST7789::SPI_DMAARRAY(uint8_t* array, size_t count) {
  _spi->DMAtransfer(array, count);
}
//画线-----
void STM_ST7789::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
  uint16_t color) {
  if ((x1 >= 0) && (x0 < _width) && (y1 >= 0) && (y0 < _height)) {
    setAddrWindow(x0, y0, x1, y1);
    writeColor(color, x1 * y1);
  }
}
//传入一组像素 8位
void STM_ST7789::writearray(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t* color) {
  drawarray(x, y, w, h, color);
}
//用一种颜色完全填充屏幕。如果需要，在子类中更新！
void STM_ST7789::fillScreen(uint16_t color) {
  fillRect(0, 0, _width, _height, color);
}
//画线
void STM_ST7789::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
  uint16_t color) {
  if (x0 == x1) {
    if (y0 > y1)
      _swap_int16_t(y0, y1);
    drawFastVLine(x0, y0, y1 - y0 + 1, color);
  }
  else if (y0 == y1) {
    if (x0 > x1)
      _swap_int16_t(x0, x1);
    drawFastHLine(x0, y0, x1 - x0 + 1, color);
  }
  else {
    SPI_BEGIN_TRANSACTION();
    writeLine(x0, y0, x1, y1, color);
    SPI_END_TRANSACTION();
  }
}

//绘制圆形轮廓
void STM_ST7789::drawCircle(int16_t x0, int16_t y0, int16_t r,
  uint16_t color) {
  int16_t f = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x = 0;
  int16_t y = r;
  SPI_BEGIN_TRANSACTION();
  writePixel(x0, y0 + r, color);
  writePixel(x0, y0 - r, color);
  writePixel(x0 + r, y0, color);
  writePixel(x0 - r, y0, color);
  while (x < y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    writePixel(x0 + x, y0 + y, color);
    writePixel(x0 - x, y0 + y, color);
    writePixel(x0 + x, y0 - y, color);
    writePixel(x0 - x, y0 - y, color);
    writePixel(x0 + y, y0 + x, color);
    writePixel(x0 - y, y0 + x, color);
    writePixel(x0 + y, y0 - x, color);
    writePixel(x0 - y, y0 - x, color);
  }
  SPI_END_TRANSACTION();
}

//四分之一圆形抽屉，用于做圆形和圆形
void STM_ST7789::drawCircleHelper(int16_t x0, int16_t y0, int16_t r,
  uint8_t cornername, uint16_t color) {
  int16_t f = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x = 0;
  int16_t y = r;

  while (x < y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    if (cornername & 0x4) {
      writePixel(x0 + x, y0 + y, color);
      writePixel(x0 + y, y0 + x, color);
    }
    if (cornername & 0x2) {
      writePixel(x0 + x, y0 - y, color);
      writePixel(x0 + y, y0 - x, color);
    }
    if (cornername & 0x8) {
      writePixel(x0 - y, y0 + x, color);
      writePixel(x0 - x, y0 + y, color);
    }
    if (cornername & 0x1) {
      writePixel(x0 - y, y0 - x, color);
      writePixel(x0 - x, y0 - y, color);
    }
  }
}

//绘制填充颜色的圆
void STM_ST7789::fillCircle(int16_t x0, int16_t y0, int16_t r,
  uint16_t color) {
  SPI_BEGIN_TRANSACTION();
  writeFastVLine(x0, y0 - r, 2 * r + 1, color);
  fillCircleHelper(x0, y0, r, 3, 0, color);
  SPI_END_TRANSACTION();
}

//带填充物的四分之一圆形抽屉，用于圆形和圆形
void STM_ST7789::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
  uint8_t corners, int16_t delta,
  uint16_t color) {

  int16_t f = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x = 0;
  int16_t y = r;
  int16_t px = x;
  int16_t py = y;

  delta++; // Avoid some +1's in the loop

  while (x < y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    // These checks avoid double-drawing certain lines, important
    // for the SSD1306 library which has an INVERT drawing mode.
    if (x < (y + 1)) {
      if (corners & 1)
        writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color);
      if (corners & 2)
        writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color);
    }
    if (y != py) {
      if (corners & 1)
        writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color);
      if (corners & 2)
        writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color);
      py = y;
    }
    px = x;
  }
}

//绘制一个没有填充颜色的矩形
void STM_ST7789::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
  uint16_t color) {
  SPI_BEGIN_TRANSACTION();
  writeFastHLine(x, y, w, color);
  writeFastHLine(x, y + h - 1, w, color);
  writeFastVLine(x, y, h, color);
  writeFastVLine(x + w - 1, y, h, color);
  SPI_END_TRANSACTION();
}

//绘制一个没有填充颜色的圆角矩形
void STM_ST7789::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
  int16_t r, uint16_t color) {
  int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
  if (r > max_radius)
    r = max_radius;
  // smarter version
  SPI_BEGIN_TRANSACTION();
  writeFastHLine(x + r, y, w - 2 * r, color);         // Top
  writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
  writeFastVLine(x, y + r, h - 2 * r, color);         // Left
  writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
  // draw four corners
  drawCircleHelper(x + r, y + r, r, 1, color);
  drawCircleHelper(x + w - r - 1, y + r, r, 2, color);
  drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
  drawCircleHelper(x + r, y + h - r - 1, r, 8, color);
  SPI_END_TRANSACTION();
}

//绘制带有填充颜色的圆角矩形
void STM_ST7789::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
  int16_t r, uint16_t color) {
  int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
  if (r > max_radius)
    r = max_radius;
  // smarter version
  SPI_BEGIN_TRANSACTION();
  writeFillRect(x + r, y, w - 2 * r, h, color);
  // draw four corners
  fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
  fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
  SPI_END_TRANSACTION();
}

//绘制一个没有填充颜色的三角形
void STM_ST7789::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
  int16_t x2, int16_t y2, uint16_t color) {
  drawLine(x0, y0, x1, y1, color);
  drawLine(x1, y1, x2, y2, color);
  drawLine(x2, y2, x0, y0, color);
}

//用颜色填充绘制三角形
void STM_ST7789::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
  int16_t x2, int16_t y2, uint16_t color) {

  int16_t a, b, y, last;
  if (y0 > y1) {
    _swap_int16_t(y0, y1);
    _swap_int16_t(x0, x1);
  }
  if (y1 > y2) {
    _swap_int16_t(y2, y1);
    _swap_int16_t(x2, x1);
  }
  if (y0 > y1) {
    _swap_int16_t(y0, y1);
    _swap_int16_t(x0, x1);
  }

  SPI_BEGIN_TRANSACTION();
  if (y0 == y2) {
    a = b = x0;
    if (x1 < a)
      a = x1;
    else if (x1 > b)
      b = x1;
    if (x2 < a)
      a = x2;
    else if (x2 > b)
      b = x2;
    writeFastHLine(a, y0, b - a + 1, color);
    SPI_END_TRANSACTION();
    return;
  }

  int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
    dx12 = x2 - x1, dy12 = y2 - y1;
  int32_t sa = 0, sb = 0;
  if (y1 == y2)
    last = y1; // Include y1 scanline
  else
    last = y1 - 1; // Skip it

  for (y = y0; y <= last; y++) {
    a = x0 + sa / dy01;
    b = x0 + sb / dy02;
    sa += dx01;
    sb += dx02;
    if (a > b)
      _swap_int16_t(a, b);
    writeFastHLine(a, y, b - a + 1, color);
  }
  sa = (int32_t)dx12 * (y - y1);
  sb = (int32_t)dx02 * (y - y0);
  for (; y <= y2; y++) {
    a = x1 + sa / dy12;
    b = x0 + sb / dy02;
    sa += dx12;
    sb += dx02;
    if (a > b)
      _swap_int16_t(a, b);
    writeFastHLine(a, y, b - a + 1, color);
  }
  SPI_END_TRANSACTION();
}

//绘制单个字符
void STM_ST7789::drawChar(int16_t x, int16_t y, uint8_t c,
  uint16_t color, uint16_t bg) {
  c -= (uint8_t)pgm_read_byte(&gfxFont->first);//获取当前字符在字库的位置
  GFXglyph* glyph = pgm_read_glyph_ptr(gfxFont, c); //提取字符glyph值
  uint8_t* bitmap = pgm_read_bitmap_ptr(gfxFont);   //获取字体位图信息
  uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
  uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height);
  int8_t xo = pgm_read_byte(&glyph->xOffset),
    yo = pgm_read_byte(&glyph->yOffset);
  uint8_t xx, yy, bits = 0, bit = 0;
  uint16_t ii = 0;
  for (yy = 0; yy < h; yy++) {
    for (xx = 0; xx < w; xx++) {
      if (!(bit++ & 7)) {
        bits = pgm_read_byte(&bitmap [bo++]);
      }
      if (bits & 0x80) {
        casualdate [ii] = color >> 8;
        casualdate [ii + 1] = color & 0xFF;
        ii += 2;
        //writePixel(x + xo + xx, y + yo + yy, color);
      }
      else {
        casualdate [ii] = bg >> 8;
        casualdate [ii + 1] = bg & 0xFF;
        ii += 2;
        //writePixel(x + xo + xx, y + yo + yy, bg);
      }
      bits <<= 1;
    }
  }
  drawarray(x + xo, y + yo, w, h, casualdate);
}
//打印一个字节/字符的数据，用于支持Print（）
size_t STM_ST7789::write(uint8_t c) {
  uint16_t unicode;
  uint8_t j = 58;
  uint16_t* dat = gfxFont->Chinese_;
  uint8_t first = gfxFont->first;
  if (c == '\n') {
    cursor_x = 0;
    cursor_y += gfxFont->yAdvance;
  }
  else if (c != '\r') {
    if (writecount != 0) {
      temparray [writecount] = c;
      writecount++;
      if (writecount == 3) {
        writecount = 0;
        unicode = ((uint8_t(int(temparray [0]) << 4)) >> 4);
        unicode = unicode << 6 | ((uint8_t(int(temparray [1]) << 2)) >> 2);
        unicode = unicode << 6 | ((uint8_t(int(temparray [2]) << 2)) >> 2);
        while (j--) {
          if (dat [j] == unicode) {
            c = 127 + j;
            j = 0;
          }
          else {
            c = 42;
          }
        }
        if ((c >= first) && (c <= (gfxFont->last))) {
          GFXglyph* glyph = pgm_read_glyph_ptr(gfxFont, c - first);
          uint8_t w = glyph->width,
            h = glyph->height;
          if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
            int16_t xo = glyph->xOffset; // sic
            if (wrap && ((cursor_x + (xo + w)) > _width)) {
              cursor_x = 0;
              cursor_y += gfxFont->yAdvance;
            }
            drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
          }
          cursor_x += glyph->xAdvance;
        }
      }
    }
    else {
      if (c > 126) {
        temparray [writecount] = c;
        writecount++;
      }
      else {
        if ((c >= first) && (c <= (gfxFont->last))) {
          GFXglyph* glyph = pgm_read_glyph_ptr(gfxFont, c - first);
          uint8_t w = glyph->width,
            h = glyph->height;
          if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
            int16_t xo = glyph->xOffset; // sic
            if (wrap && ((cursor_x + (xo + w)) > _width)) {
              cursor_x = 0;
              cursor_y += gfxFont->yAdvance;
            }
            drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
          }
          cursor_x += glyph->xAdvance;
        }
      }
    }
  }
  return 1;
}

//设置字体
void STM_ST7789::setFont(const GFXfont* f) {
  if (f) {          // 是否传入了字体结构指针？
    if (!gfxFont) { // 没有当前的字体结构？
      // 从传统字体行为切换到新字体行为。
      // 将光标位置向下移动6个像素，使其位于基线上。
      cursor_y += 6;
    }
  }
  else if (gfxFont) { // 传递了NULL。是否定义了当前字体结构？
    // 从新字体行为切换到经典字体行为。
    //将光标位置向上移动6个像素，使其位于字符的左上角。
    cursor_y -= 6;
  }
  gfxFont = (GFXfont*)f;
}
//写入字符数组
void STM_ST7789::drawmutant(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t* array, uint16_t number, uint16_t color, uint16_t bg) {
  uint16_t ii;
  uint8_t codetemp;
  for (uint8_t i = 0;i < number;i++) {
    codetemp = array [i];
    for (uint8_t j = 8;j > 0;j--) {
      if ((codetemp >> (j - 1)) & 1) {
        casualdate [ii] = color >> 8;
        casualdate [ii + 1] = color & 0xFF;
        ii += 2;
      }
      else {
        casualdate [ii] = bg >> 8;
        casualdate [ii + 1] = bg & 0xFF;
        ii += 2;
      }
      if (ii == 4096) {
        drawarray(x, y, w, h / 2, casualdate);
        ii = 0;
      }
    }

  }
  drawarray(x, y + 32, w, h / 2, casualdate);
}
//写入图片
void STM_ST7789::drawpicture(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t* array) {
  uint16_t d = 0;
  uint16_t xh = 0;
  SPI_BEGIN_TRANSACTION();
  setAddrWindow(x, y, w, h);
  if ((w * h) < 2049) {
    for (uint16_t i = 0;i < w * h;i++) {
      casualdate [d] = array [i] >> 8;
      casualdate [d + 1] = array [i] & 0xFF;
      d += 2;
    }
    SPI_DMAARRAY(casualdate, w * h * 2);
  }
  else {
    for (uint16_t i = 0;i < w * h;i++) {
      casualdate [d] = array [i] >> 8;
      casualdate [d + 1] = array [i] & 0xFF;
      d += 2;
      if (d == 4096) {
        SPI_DMAARRAY(casualdate, 4096);
        d = 0;
      }
    }
    SPI_DMAARRAY(casualdate, (w * h * 2) % 4096);
  }
  SPI_END_TRANSACTION();
}